// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;

use anyhow::Context;
use askama::Template;
use convert_case::{Case, Casing};

#[derive(Template)]
#[template(path = "test.cpp.askama")]
struct TestTemplate {
    pkg_name: String,
    msg_name: String,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    println!("cargo:rerun-if-changed=templates/test.cpp.askama");

    let msgs_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../idl/msg");
    let tests_cpp_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests");
    tokio::fs::create_dir_all(&tests_cpp_dir).await
        .context("failed to create tests directory")?;

    let mut read_msgs_dir = tokio::fs::read_dir(&msgs_dir).await
        .context("failed to read message directory")?;
    while let Some(entry) = read_msgs_dir.next_entry().await? {
        let file_type = entry.file_type().await?;
        if !file_type.is_dir() {
            continue;
        }

        let pkg_dir = entry.path();
        let pkg_name = pkg_dir.file_name().unwrap().to_str().unwrap();

        let mut read_msg_dir = tokio::fs::read_dir(&pkg_dir).await
            .context(format!("failed to read directory {}", pkg_dir.display()))?;
        while let Some(entry) = read_msg_dir.next_entry().await? {
            let file_type = entry.file_type().await?;
            if !file_type.is_file() {
                continue;
            }

            let msg_file = entry.path();
            let msg_name = msg_file.file_stem().unwrap().to_str().unwrap();
            println!("cargo:rerun-if-changed=../../../idl/msg/{}/{}.msg", pkg_name, msg_name);

            let template = TestTemplate {
                pkg_name: pkg_name.to_string(),
                msg_name: msg_name.to_case(Case::Pascal),
            };
            let content = template.render()
                .context(format!("failed to render test template for {}/{}", pkg_name, msg_name))?;
            let out_path = tests_cpp_dir.join(format!("{}_{}.cpp", pkg_name, msg_name.to_case(Case::Snake)));
            if !out_path.exists() || tokio::fs::read_to_string(&out_path).await.is_ok_and(|s| s != content) {
                tokio::fs::write(out_path, content).await
                    .context(format!("failed to write test template for {}/{}", pkg_name, msg_name))?;
            }
        }
    }

    Ok(())
}
